package view_server

import (
	"bigdevops/src/cache"
	"bigdevops/src/common"
	"bigdevops/src/config"
	"bigdevops/src/models"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/json"
	"sigs.k8s.io/yaml"
	"sort"
	"strconv"
	"strings"
)

type OneConfigmap struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	Age       string `json:"age"`

	LabelPairs  map[string]string `json:"labelPairs"`
	Labels      []string          `json:"labels"`
	LabelsFront string            `json:"labelsFront"`

	FileNum   int                 `json:"fileNum"`
	CmDataMap map[string]string   `json:"cmDataMap"`
	DataArray []*ConfigmapOneFile `json:"dataArray"`
}

type ConfigmapOneFile struct {
	FileName string `json:"fileName"`
	Content  string `json:"content"`
	Id       int    `json:"id"`
}

type ConfigmapUpdateOne struct {
	DataArray []*ConfigmapOneFile `json:"dataArray"`
	*common.K8sModOneObjCommonRequest
}

func getK8sConfigmapListByNs(c *gin.Context) {

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	currentPage, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	sortFiled := c.DefaultQuery("field", "")
	orderType := c.DefaultQuery("order", "")

	// 集群的名称
	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("name", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	if searchNamespace == common.K8S_NS_ALL_KEY {
		searchNamespace = ""
	}

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	mSet := kc.GetClusterMetricsClientSetById(dbObj.ID)
	if mSet == nil {
		sc.Logger.Error("根据id找k8s集群metricsSet缓存错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()
	cmItems, err := kSet.CoreV1().ConfigMaps(searchNamespace).List(ctx1, metav1.ListOptions{})
	if err != nil {
		sc.Logger.Error("根据ik8s集群kset获取节点错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 进行搜索
	filterResults := []corev1.ConfigMap{}
	for _, cm := range cmItems.Items {
		if searchName != "" && !strings.Contains(cm.Name, searchName) {
			continue
		}
		filterResults = append(filterResults, cm)

	}

	//startIndex, endIndex
	startIndex := (pageSize) * (currentPage - 1)
	endIndex := startIndex + pageSize
	if endIndex > len(filterResults) {
		endIndex = len(filterResults)
	}

	// 转化一下
	finalRes := []*OneConfigmap{}
	pageResult := filterResults[startIndex:endIndex]

	for _, obj := range pageResult {
		one := configmapConvert(obj)
		finalRes = append(finalRes, one)
	}
	// 排序
	if sortFiled == "name" {

		sort.SliceStable(finalRes, func(i, j int) bool {
			if orderType == "ascend" {
				return finalRes[i].Name < finalRes[j].Name
			} else {
				return finalRes[i].Name > finalRes[j].Name
			}

		})
	}

	resp := &ResponseResourceCommon{
		//Total: models.GetK8sClusterCount(), 因为是带了查询条件的 所以 count 不能是all 而是 过滤后的total

		Total: len(filterResults),
		Items: finalRes,
	}

	common.OkWithDetailed(resp, "ok", c)
}

func configmapConvert(cm corev1.ConfigMap) *OneConfigmap {
	res := &OneConfigmap{
		Name:      cm.Name,
		Namespace: cm.Namespace,
		Age:       translateTimestampSince(cm.CreationTimestamp),
	}

	res.Labels = common.GenStringArrayByMap(cm.Labels)
	res.LabelsFront = strings.Join(res.Labels, "\n")
	res.FileNum = len(cm.Data)
	res.CmDataMap = cm.Data
	dr := []*ConfigmapOneFile{}
	num := 0
	for k, v := range cm.Data {
		num++
		dr = append(dr, &ConfigmapOneFile{
			FileName: k,
			Content:  v,
			Id:       num,
		})

	}
	res.DataArray = dr

	return res
}

func k8sUpdateConfigmapDataOne(c *gin.Context) {
	//kset *kubernetes.Clientset, podName string, containerName string, ns string string
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	var reqObj ConfigmapUpdateOne
	err := c.ShouldBindJSON(&reqObj)
	if err != nil {
		sc.Logger.Error("解析k8sUpdateConfigmapDataOne配置请求失败", zap.Any("k8s配置", reqObj), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 在这里校验字段，是否必填，范围是否正确
	err = validate.Struct(reqObj)
	if err != nil {

		// 这里为什么要判断错误是否是 ValidationErrors
		if errors, ok := err.(validator.ValidationErrors); ok {
			common.ReqBadFailWithWithDetailed(

				gin.H{
					"翻译前": err.Error(),
					"翻译后": errors.Translate(trans),
				},
				"请求出错",
				c,
			)
			return
		}
		common.ReqBadFailWithMessage(err.Error(), c)
		return

	}

	//searchCluster := c.DefaultQuery("cluster", "")
	searchCluster := reqObj.Cluster
	//searchName := c.DefaultQuery("name", "")
	searchName := reqObj.Name

	//searchNamespace := c.DefaultQuery("namespace", "")
	searchNamespace := reqObj.Namespace
	//searchContainer := c.DefaultQuery("container", "")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	ctx1, canFun1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer canFun1()
	cm, err := kSet.CoreV1().ConfigMaps(searchNamespace).Get(ctx1, searchName, metav1.GetOptions{})
	if err != nil {
		msg := fmt.Sprintf("更新cm的data前置获取对象错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	tmpM := map[string]string{}
	for _, one := range reqObj.DataArray {
		one := one
		tmpM[one.FileName] = one.Content
	}
	cm.Data = tmpM

	_, err = kSet.CoreV1().ConfigMaps(searchNamespace).Update(ctx1, cm, metav1.UpdateOptions{})
	if err != nil {
		msg := fmt.Sprintf("更新cm的data错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	common.OkWithMessage("更新成功", c)

}

func getK8sConfigmapYamlOne(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("name", "")

	searchNamespace := c.DefaultQuery("namespace", "")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()
	cm, err := kSet.CoreV1().ConfigMaps(searchNamespace).Get(ctx1, searchName, metav1.GetOptions{})
	//fmt.Println(pod)
	cm.APIVersion = "v1"
	cm.Kind = "ConfigMap"
	cm.ManagedFields = nil

	if err != nil {
		msg := fmt.Sprintf("根据id找k8s集群get-cm错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	jsonBytes, err := json.Marshal(cm)
	if err != nil {
		msg := fmt.Sprintf("根据cm对象jsonMarshal错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}
	y, err := yaml.JSONToYAML(jsonBytes)
	if err != nil {
		msg := fmt.Sprintf("根据cm对象jsonyaml.JSONToYAML错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	common.OkWithData(string(y), c)
}

func k8sBatchDeleteConfigmap(c *gin.Context) {
	//kset *kubernetes.Clientset, podName string, containerName string, ns string string
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	var reqObj common.K8sBatchRequestCommon
	err := c.ShouldBindJSON(&reqObj)
	if err != nil {
		sc.Logger.Error("解析批量删除Deployment请求失败", zap.Any("k8s配置", reqObj), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 在这里校验字段，是否必填，范围是否正确
	err = validate.Struct(reqObj)
	if err != nil {

		// 这里为什么要判断错误是否是 ValidationErrors
		if errors, ok := err.(validator.ValidationErrors); ok {
			common.ReqBadFailWithWithDetailed(

				gin.H{
					"翻译前": err.Error(),
					"翻译后": errors.Translate(trans),
				},
				"请求出错",
				c,
			)
			return
		}
		common.ReqBadFailWithMessage(err.Error(), c)
		return

	}

	//searchCluster := c.DefaultQuery("cluster", "")
	searchCluster := reqObj.Cluster

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	for _, item := range reqObj.Items {
		item := item
		ctx1, canFun1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
		defer canFun1()
		err := kSet.CoreV1().ConfigMaps(item.Namespace).Delete(ctx1, item.Name, metav1.DeleteOptions{})
		if err != nil {
			msg := fmt.Sprintf("删除cm错误:ns:%v name:%v %v", item.Namespace, item.Name, err.Error())
			sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
			common.FailWithMessage(msg, c)
			return
		}

	}

	common.OkWithMessage("删除成功", c)

}
